import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'node:crypto'

/**
 * 计算SHA1签名
 * @param params
 */
export function getSha1Signature(params: Record<string, string | number>, sep = ''): string {
    const base_str = Object.entries(params)
        .filter(([_, value]) => typeof value === 'string' || typeof value === 'number')
        .sort(([k1], [k2]) => k1.localeCompare(k2))
        .map(([_, value]) => String(value))
        .join(sep)

    return createHash('SHA1').update(base_str).digest('hex').toLowerCase()
}

/**
 * 消息体解密
 * @param encrypted 密文
 * @param aes_key 解密用的aes密钥
 */
export function decrpytMsg(
    encrypted: string,
    aes_key: string,
): {
    decrypted: string
    app_id: string
} {
    const key = Buffer.from(`${aes_key}=`, 'base64')
    const iv = key.toString('hex').substring(0, 16)
    const decipher = createDecipheriv('aes-256-cbc', key, iv)
    decipher.setAutoPadding(false)
    const output = Buffer.concat([decipher.update(encrypted, 'base64'), decipher.final()])

    let pad = output.at(output.length - 1)!
    if (pad < 1 || pad > 32) pad = 0

    const msg_length = output.readInt32BE(16)
    const decrypted = output.subarray(20, 20 + msg_length).toString('utf-8')
    const app_id = output.subarray(20 + msg_length, output.length - pad).toString('utf-8')
    return {
        decrypted,
        app_id,
    }
}

/**
 * 加密消息体
 * @param raw
 * @param aes_key
 * @param app_id
 */
export function encryptMsg(raw: string, aes_key: string, app_id: string): string {
    const chunks: Buffer[] = [randomBytes(16)]

    const msg_bytes = Buffer.from(raw, 'utf-8')
    const length_bytes = Buffer.alloc(4)
    length_bytes.writeInt32BE(msg_bytes.byteLength)
    chunks.push(length_bytes, msg_bytes)
    chunks.push(Buffer.from(app_id, 'utf-8'))

    //补位
    const total_length = chunks.reduce((size: number, chunk: Buffer) => size + chunk.byteLength, 0)

    const mod = total_length % 32
    const pad = 32 - mod

    chunks.push(Buffer.alloc(pad).fill(pad))

    const all = Buffer.concat(chunks)

    //加密
    const key = Buffer.from(`${aes_key}=`, 'base64')
    const iv = key.toString('hex').substring(0, 16)
    const cipher = createCipheriv('aes-256-cbc', key, iv)
    cipher.setAutoPadding(false)

    return Buffer.concat([cipher.update(all), cipher.final()]).toString('base64')
}
